package com.meida.module.push.provider.service;

import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.Message;
import cn.jpush.api.push.model.Options;
import cn.jpush.api.push.model.Platform;
import cn.jpush.api.push.model.PushPayload;
import cn.jpush.api.push.model.audience.Audience;
import cn.jpush.api.push.model.notification.AndroidNotification;
import cn.jpush.api.push.model.notification.IosNotification;
import cn.jpush.api.push.model.notification.Notification;
import com.meida.common.base.service.BasePushService;
import com.meida.common.base.utils.FlymeUtils;
import com.meida.common.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author flyme
 * @date 2019/10/15 15:57
 */
@Slf4j
@Component("PUSH_JG")
public class JPushService<K extends JPushClient> implements BasePushService<K> {
    public static final int SUCCESS = 200;

    private JPushClient jPushClient;
    /*****环境**/
    private boolean ambient = false;

    @Override
    public void init(K jPushClient, boolean ambient) {
        this.jPushClient = jPushClient;
        this.ambient = ambient;
    }

    /**
     * 推送给设备标识参数的用户
     *
     * @param deviceToken       设备标识
     * @param notificationTitle 通知内容标题
     * @param title             消息内容标题
     * @param content           消息内容
     * @param extra             扩展字段
     * @return 0推送失败，1推送成功
     */
    @Override
    public int sendByDeviceToken(Object deviceToken, String notificationTitle, String title, String content, Map extra) {
        int result = 0;
        if (FlymeUtils.isNotEmpty(deviceToken)) {
            List<String> alias = new ArrayList<>();
            alias.add(deviceToken.toString());
            result = sendByListTokey(alias, notificationTitle, title, content, extra);
        }
        return result;
    }


    /**
     * 推送给设备标识参数的用户
     *
     * @param deviceToken       设备标识
     * @param notificationTitle 通知内容标题
     * @param title             消息内容标题
     * @param content           消息内容
     * @param extra             扩展字段
     * @return 0推送失败，1推送成功
     */
    @Override
    public int sendByListTokey(List<String> deviceToken, String notificationTitle, String title, String content, Map extra) {
        int result = 0;
        try {
            PushPayload pushPayload = this.getPushPayload(deviceToken, notificationTitle, title, content, extra);
            log.debug("推送内容:{}", pushPayload.toJSON());
            PushResult pushResult = jPushClient.sendPush(pushPayload);
            log.debug("推送结果:{}", pushResult.toString());
            if (pushResult.getResponseCode() == SUCCESS) {
                result = 1;
            }
        } catch (APIConnectionException e) {
            e.printStackTrace();

        } catch (APIRequestException e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 发送给所有安卓用户
     *
     * @param notificationTitle 通知内容标题
     * @param title             消息内容标题
     * @param content           消息内容
     * @param extra             扩展字段
     * @return 0推送失败，1推送成功
     */
    public int sendAllAndroid(String notificationTitle, String title, String content, Map extra) {
        int result = 0;
        try {
            PushPayload pushPayload = this.getPushPayloadByAndroid(notificationTitle, title, content, extra);
            log.debug("推送内容:{}", pushPayload.toJSON());
            PushResult pushResult = jPushClient.sendPush(pushPayload);
            log.debug("推送结果:{}", pushResult.toString());
            if (pushResult.getResponseCode() == SUCCESS) {
                result = 1;
            }
        } catch (Exception e) {

            e.printStackTrace();
        }

        return result;
    }

    /**
     * 发送给所有IOS用户
     *
     * @param notificationTitle 通知内容标题
     * @param title             消息内容标题
     * @param content           消息内容
     * @param extra             扩展字段
     * @return 0推送失败，1推送成功
     */
    public int sendAllIos(String notificationTitle, String title, String content, Map extra) {
        int result = 0;
        try {
            PushPayload pushPayload = this.getPushPayloadByIos(notificationTitle, title, content, extra);
            log.debug("推送内容:{}", pushPayload.toJSON());
            PushResult pushResult = jPushClient.sendPush(pushPayload);
            log.debug("推送结果:{}", pushResult.toString());
            if (pushResult.getResponseCode() == SUCCESS) {
                result = 1;
            }
        } catch (Exception e) {

            e.printStackTrace();
        }

        return result;
    }

    /**
     * 发送给所有用户
     *
     * @param notificationTitle 通知内容标题
     * @param title             消息内容标题
     * @param content           消息内容
     * @param extra             扩展字段
     * @return 0推送失败，1推送成功
     */
    public int sendAll(String notificationTitle, String title, String content, Map extra) {
        int result = 0;
        try {
            PushPayload pushPayload = this.getPushPayloadByAndroidAndIos(notificationTitle, title, content, extra);
            log.debug("推送内容:{}", pushPayload.toJSON());
            PushResult pushResult = jPushClient.sendPush(pushPayload);
            log.debug("推送结果:{}", pushResult.toString());
            if (pushResult.getResponseCode() == 200) {
                result = 1;
            }
        } catch (Exception e) {

            e.printStackTrace();
        }

        return result;
    }

    @Override
    public int sendByDeviceType(int deviceType, String notificationTitle, String title, String content, Map extra) {
        Integer result = 0;
        switch (deviceType) {
            case 0:
                result = sendAll(notificationTitle, title, content, extra);
                break;
            case 1:
                result = sendAllAndroid(notificationTitle, title, content, extra);
                break;
            case 2:
                result = sendAllIos(notificationTitle, title, content, extra);
                break;
        }
        return result;
    }


    private PushPayload getPushPayload(List<String> deviceToken, String notificationTitle, String title, String content, Map extra) {

        //创建一个IosAlert对象，可指定APNs的alert、title等字段
        //IosAlert iosAlert =  IosAlert.newBuilder().setTitleAndBody("title", "alert body").build();

        return PushPayload.newBuilder()
                //指定要推送的平台，all代表当前应用配置了的所有平台，也可以传android等具体平台
                .setPlatform(Platform.all())
                //指定推送的接收对象，all代表所有人，也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的deviceToken
                .setAudience(Audience.registrationId(deviceToken)).setAudience(Audience.alias(deviceToken))
                //jpush的通知，android的由jpush直接下发，iOS的由apns服务器下发，Winphone的由mpns下发
                .setNotification(Notification.newBuilder()
                        .setAlert(notificationTitle)
                        //指定当前推送的android通知
                        .addPlatformNotification(AndroidNotification.newBuilder()
                                .setAlert(title)
                                .setTitle(notificationTitle)
                                //此字段为透传字段，不会显示在通知栏。用户可以通过此字段来做一些定制需求，如特定的key传要指定跳转的页面（value）
                                .addExtra("extra", JsonUtils.beanToJson(extra))
                                .build())
                        //指定当前推送的iOS通知
                        .addPlatformNotification(IosNotification.newBuilder()
                                //传一个IosAlert对象，指定apns title、title、subtitle等
                                .setAlert(notificationTitle)
                                //直接传alert
                                //此项是指定此推送的badge自动加1
                                .incrBadge(1)
                                //此字段的值default表示系统默认声音；传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒，
                                // 如果系统没有此音频则以系统默认声音提醒；此字段如果传空字符串，iOS9及以上的系统是无声音提醒，以下的系统是默认声音
                                .setSound("sound.caf")
                                //此字段为透传字段，不会显示在通知栏。用户可以通过此字段来做一些定制需求，如特定的key传要指定跳转的页面（value）
                                .addExtra("extra", JsonUtils.beanToJson(extra))
                                //此项说明此推送是一个background推送，想了解background看：http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification
                                //取消此注释，消息推送时ios将无法在锁屏情况接收
                                // .setContentAvailable(true)
                                .build())
                        .build())
                //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息，
                // sdk默认不做任何处理，不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
                // [通知与自定义消息有什么区别？]了解通知和自定义消息的区别
                .setMessage(Message.newBuilder()
                        .setMsgContent(content)
                        .setTitle(title)
                        .addExtra("extra", JsonUtils.beanToJson(extra))
                        .build())
                .setOptions(Options.newBuilder()
                        //此字段的值是用来指定本推送要推送的apns环境，false表示开发，true表示生产；对android和自定义消息无意义
                        .setApnsProduction(ambient)
                        //此字段是给开发者自己给推送编号，方便推送者分辨推送记录
                        .setSendno(1)
                        //此字段的值是用来指定本推送的离线保存时长，如果不传此字段则默认保存一天，最多指定保留十天；
                        .setTimeToLive(86400)
                        .build())
                .build();

    }

    private PushPayload getPushPayloadByAndroid(String notificationTitle, String title, String content, Map extra) {
        return PushPayload.newBuilder()
                //指定要推送的平台，all代表当前应用配置了的所有平台，也可以传android等具体平台
                .setPlatform(Platform.android())
                //指定推送的接收对象，all代表所有人，也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
                .setAudience(Audience.all())
                //jpush的通知，android的由jpush直接下发，iOS的由apns服务器下发，Winphone的由mpns下发
                .setNotification(Notification.newBuilder()
                        //指定当前推送的android通知
                        .addPlatformNotification(AndroidNotification.newBuilder()
                                .setAlert(title)
                                .setTitle(notificationTitle)
                                //此字段为透传字段，不会显示在通知栏。用户可以通过此字段来做一些定制需求，如特定的key传要指定跳转的页面（value）
                                .addExtra("extra", JsonUtils.beanToJson(extra))
                                .build())
                        .build()
                )
                //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息，
                // sdk默认不做任何处理，不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
                // [通知与自定义消息有什么区别？]了解通知和自定义消息的区别
                .setMessage(Message.newBuilder()
                        .setMsgContent(content)
                        .setTitle(title)
                        .addExtra("extra", JsonUtils.beanToJson(extra))
                        .build())

                .setOptions(Options.newBuilder()
                        //此字段的值是用来指定本推送要推送的apns环境，false表示开发，true表示生产；对android和自定义消息无意义
                        .setApnsProduction(ambient)
                        //此字段是给开发者自己给推送编号，方便推送者分辨推送记录
                        .setSendno(1)
                        //此字段的值是用来指定本推送的离线保存时长，如果不传此字段则默认保存一天，最多指定保留十天，单位为秒
                        .setTimeToLive(86400)
                        .build())
                .build();
    }

    private PushPayload getPushPayloadByIos(String notificationTitle, String title, String content, Map extra) {
        return PushPayload.newBuilder()
                //指定要推送的平台，all代表当前应用配置了的所有平台，也可以传android等具体平台
                .setPlatform(Platform.ios())
                //指定推送的接收对象，all代表所有人，也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
                .setAudience(Audience.all())
                //jpush的通知，android的由jpush直接下发，iOS的由apns服务器下发，Winphone的由mpns下发
                .setNotification(Notification.newBuilder()
                        .setAlert(notificationTitle)
                        //指定当前推送的android通知
                        .addPlatformNotification(IosNotification.newBuilder()
                                //传一个IosAlert对象，指定apns title、title、subtitle等
                                .setAlert(title)
                                //直接传alert
                                //此项是指定此推送的badge自动加1
                                .incrBadge(1)
                                //此字段的值default表示系统默认声音；传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒，
                                // 如果系统没有此音频则以系统默认声音提醒；此字段如果传空字符串，iOS9及以上的系统是无声音提醒，以下的系统是默认声音
                                .setSound("sound.caf")
                                //此字段为透传字段，不会显示在通知栏。用户可以通过此字段来做一些定制需求，如特定的key传要指定跳转的页面（value）
                                .addExtra("extra", JsonUtils.beanToJson(extra))
                                //此项说明此推送是一个background推送，想了解background看：http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification
                                // .setContentAvailable(true)

                                .build())
                        .build()
                )
                //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息，
                // sdk默认不做任何处理，不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
                // [通知与自定义消息有什么区别？]了解通知和自定义消息的区别
                .setMessage(Message.newBuilder()
                        .setMsgContent(content)
                        .setTitle(title)
                        .addExtra("extra", JsonUtils.beanToJson(extra))
                        .build())

                .setOptions(Options.newBuilder()
                        //此字段的值是用来指定本推送要推送的apns环境，false表示开发，true表示生产；对android和自定义消息无意义
                        .setApnsProduction(ambient)
                        //此字段是给开发者自己给推送编号，方便推送者分辨推送记录
                        .setSendno(1)
                        //此字段的值是用来指定本推送的离线保存时长，如果不传此字段则默认保存一天，最多指定保留十天，单位为秒
                        .setTimeToLive(86400)
                        .build())
                .build();
    }

    public PushPayload getPushPayloadByAndroidAndIos(String notificationTitle, String title, String content, Map extra) {
        return PushPayload.newBuilder()
                .setPlatform(Platform.android_ios())
                .setAudience(Audience.all())
                .setNotification(Notification.newBuilder()
                        .setAlert(notificationTitle)
                        .addPlatformNotification(AndroidNotification.newBuilder()
                                .setAlert(title)
                                .setTitle(notificationTitle)
                                //此字段为透传字段，不会显示在通知栏。用户可以通过此字段来做一些定制需求，如特定的key传要指定跳转的页面（value）
                                .addExtra("extra", JsonUtils.beanToJson(extra))
                                .build()
                        )
                        .addPlatformNotification(IosNotification.newBuilder()
                                //传一个IosAlert对象，指定apns title、title、subtitle等
                                .setAlert(title)
                                //直接传alert
                                //此项是指定此推送的badge自动加1
                                .incrBadge(1)
                                //此字段的值default表示系统默认声音；传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒，
                                // 如果系统没有此音频则以系统默认声音提醒；此字段如果传空字符串，iOS9及以上的系统是无声音提醒，以下的系统是默认声音
                                .setSound("sound.caf")
                                //此字段为透传字段，不会显示在通知栏。用户可以通过此字段来做一些定制需求，如特定的key传要指定跳转的页面（value）
                                .addExtra("extray", JsonUtils.beanToJson(extra))
                                //此项说明此推送是一个background推送，想了解background看：http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification
                                // .setContentAvailable(true)

                                .build()
                        )
                        .build()
                )
                //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息，
                // sdk默认不做任何处理，不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
                // [通知与自定义消息有什么区别？]了解通知和自定义消息的区别
                .setMessage(Message.newBuilder()
                        .setMsgContent(content)
                        .setTitle(title)
                        .addExtra("extra", JsonUtils.beanToJson(extra))
                        .build())

                .setOptions(Options.newBuilder()
                        //此字段的值是用来指定本推送要推送的apns环境，false表示开发，true表示生产；对android和自定义消息无意义
                        .setApnsProduction(ambient)
                        //此字段是给开发者自己给推送编号，方便推送者分辨推送记录
                        .setSendno(1)
                        //此字段的值是用来指定本推送的离线保存时长，如果不传此字段则默认保存一天，最多指定保留十天，单位为秒
                        .setTimeToLive(86400)
                        .build()
                )
                .build();
    }
}
